package com.fanketly.musicdiary.domain

import android.util.Log
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.fanketly.musicdiary.data.MusicEventListener
import com.fanketly.musicdiary.data.TAG
import com.fanketly.musicdiary.data.model.MusicModel
import com.fanketly.musicdiary.data.repository.MusicRepo
import com.lzx.starrysky.OnPlayProgressListener
import com.lzx.starrysky.OnPlayerEventListener
import com.lzx.starrysky.SongInfo
import com.lzx.starrysky.StarrySky
import com.lzx.starrysky.manager.PlaybackStage
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject

/**
 *音乐播放通过StarrySky实现
 *Api地址https://github.com/EspoirX/StarrySky/blob/androidx/readme/StarrySky%E4%BB%8B%E7%BB%8D.md
 **/
@HiltViewModel
class MusicViewModel @Inject constructor(private val repo: MusicRepo) : ViewModel() {
    init {
        setMusicListFromOtherScreen()
    }

    /**
     *数据库内容改变时会重新发送，而热流则会一直收集内容，经过map处理后通知订阅的ui
     **/
    val uiState: StateFlow<MusicUiState> = getAll().map {
        Log.i(TAG, "uiState:${it.size} ")
        if (musicList?.size != it.size) musicList = it
        MusicUiState.Success(it)
    }.stateIn(//stateIn converts data flow to StateFlow
        scope = viewModelScope,
        //configures a delay (in milliseconds) between the disappearance of the last subscriber and the stopping of the sharing coroutine. It defaults to zero (stop immediately).
        started = SharingStarted.WhileSubscribed(5000),
        initialValue = MusicUiState.UnKnown
    )

    /**
     *此举是为了方便在viewModel里重复使用list
     **/
    private var musicList: List<MusicModel>? = null

    /**
     *初始化为了在音乐列表没初始化时可以播放音乐
     **/
    private fun setMusicListFromOtherScreen() {
        viewModelScope.launch {
            getAll().collect {
                musicList = it
                Log.i(TAG, "setMusicListFromOtherScreen:${musicList?.size} ")
            }
//                .first {
//                it.isNotEmpty()
//            }

//            getAll().collect {
//                musicList = it
//                Log.i(TAG, "setMusicListFromOtherScreen:${musicList?.size} ")
//            }
        }
    }

    private fun getAll() = repo.getAll()

    //used to get whether music is playing
    private val _isPlaying = mutableStateOf(StarrySky.with().isPlaying())
    val isPlaying
        get() = _isPlaying.value

    //get music playback progress
    private val _musicProcess = mutableStateOf(0f)
    val musicProcess
        get() = _musicProcess.value

    private val _musicInfo = mutableStateOf<SongInfo?>(null)
    val musicInfo
        get() = _musicInfo.value

    /**
     *滑动一定距离时隐藏歌曲信息框
     **/
    private val _isShowSongDetail = mutableStateOf(true)
    val isShowSongDetail
        get() = _isShowSongDetail.value

    fun hideSongDetail() {
        _isShowSongDetail.value = false
    }

    fun showSongDetail() {
        _isShowSongDetail.value = true
    }

    init {
        //monitor music playback status
        StarrySky.with().addPlayerEventListener(object : OnPlayerEventListener {
            override fun onPlaybackStageChange(stage: PlaybackStage) {
//                Log.i(TAG, "onPlaybackStageChange: ${stage.stage}")
                when (stage.stage) {
                    PlaybackStage.PLAYING -> {
                        _isPlaying.value = true
                        _musicInfo.value = stage.songInfo
                    }
                    PlaybackStage.PAUSE -> {
                        _isPlaying.value = false
                    }
                    PlaybackStage.IDLE -> {
                        _isPlaying.value = false
                        _musicProcess.value = 0f
                    }
                }
            }

        }, MusicEventListener)
        //monitor music playback progress
        StarrySky.with().setOnPlayProgressListener(object : OnPlayProgressListener {
            override fun onPlayProgress(currPos: Long, duration: Long) {
                _musicProcess.value = (currPos.toFloat() / duration)
                Log.i(TAG, "onPlayProgress: $musicProcess")
            }
        })
    }


    /**
     *根据心情更新歌曲
     **/
    suspend fun updateMusic(mood: String): String? {
        return repo.update(mood)
    }


    fun playMusicByInfo(info: SongInfo) {
//        _isPlaying.value = _isPlaying.value.not()
//        Log.i(TAG, "playMusicByInfo: ${info.songUrl}")
        with(StarrySky.with()) {
            if (getNowPlayingSongInfo() != null && getNowPlayingSongInfo()!!.songUrl == info.songUrl) {
                Log.i(TAG, "playMusicByInfo: 因为重复添加 跳出方法,${info.songName}")
                return
            }
            playMusicByInfo(info)
        }
    }


    fun playMusicByID(id: String) {
        Log.i(TAG, "playMusicByID: $id")
        musicList?.find { it.musicID == id }?.let {
            playMusicByInfo(it.musicInfo)
        }
    }


    fun pauseOrRestoreMusic() {
        if (isPlaying) {
            StarrySky
                .with()
                .pauseMusic()
        } else {
            StarrySky
                .with()
                .restoreMusic()
        }
    }

    override fun onCleared() {
        super.onCleared()
        //remove status listener when exiting
        StarrySky.with().removePlayerEventListener(MusicEventListener)
    }
}